/* 
	Essno is an elliptic curve cryptography base software
	Popov AS, 2009
*/ 

#include <stdio.h>		// Стандартный Ввод/Вывод
#include <stdlib.h>		// Ген. сл. ч.
#include <time.h>		// time для генератора случайного подкл. к потоку
#include <string.h>		// Быстрая работа с памятью memset
#include <getopt.h>		// Обработка переданных опций для ПО
//#include <asm.h>
#include "type_ess.h"
#include "essno.h" 


        
int main (int argc, char *argv[])
{
	testt=0;
	/*Обработка опций и аргументов, переданных программе*/
	FILE *keyfile;
	FILE *infile = stdin;
	FILE *outfile = stdout;
	char flag = '0';
	int  opt;
	char *fnamekey = NULL;		//Показатели наличия переданного файла
	char *fnamein = NULL;
	char *fnameout = NULL;
	char help_str[] = 
       "Essno 0.0.0, программа проверки и создания ЭЦП      \n"
       "Использование: essno [-e, -d]  -k FILE  -i FILE  -o FILE 			\n"
       "\n"
       "В настоящий момент программа не является работоспособной в должной мере.    \n"
       "  (обнаружена ошибка нахождения обратного числа в алгоритме Евклида) \n"
       "  (в настоящее время идёт исправление этой ошибки) \n"
       "\n"
       "-t, --test               - Запустить в тестовом режиме \n"
       "-h, --help               - Вывести эту справку и выйти \n"
       "-e, --encrypt            - Создание ЭЦП \n"
       "-d, --decrypt            - Проверка ЭЦП \n"
       "-k, --key ФАЙЛ           - Содержит параметры кривой и ключ (для генерации или проверки) \n"
       "-i, --input-file ФАЙЛ    - Обрабатываемый файл (сообщение) \n"
       "-o, --output-file ФАЙЛ   - Результат работы (ЭЦП или итог проверки)\n";
	const struct option long_opts[] = {
		{ "test", no_argument, NULL, 't' },
		{ "help", no_argument, NULL, 'h' },
		{ "encrypt", no_argument, NULL, 'e' },
		{ "decrypt", no_argument, NULL, 'd' },
		{ "key", required_argument, NULL, 'k' },
		{ "input-file", required_argument, NULL, 'i' },
		{ "output-file", required_argument, NULL, 'o' },
		{ NULL, 0, NULL, 0 }
	};

	/*Обрабатываем опции*/
	while ((opt = getopt_long (argc, argv, "thedk:i:o:",
                            long_opts, NULL)) != -1) {
		switch (opt) {
			case 't':
				testt=1;
				goto test;
			break;
			
			case 'h':
				printf ("%s", help_str);
			return 0;

			case 'e':
				flag = 'e';
			break;

			case 'd':
				flag = 'd';
			break;

			case 'k':
				fnamekey = optarg;
				printf("\nfnamekey=%s", fnamekey);
			break;

			case 'i':
				fnamein = optarg;
				printf("\nfnamein=%s", fnamein);
			break;

			case 'o':
				fnameout = optarg;
				printf("\nfnameout=%s", fnameout);
			break;

			case '?':
				fprintf (stderr, "%s", help_str);
			return 1;

			default:
				fprintf (stderr, "Неизвестная ошибка!\n");
			return 1;
		}
	};
       
	if( !(flag=='e' || flag=='d') ){
		fprintf (stderr,"Укажите режим работы программы \n%s", help_str);
		return 1;		   				
	};


	/*Открываем файлы (параметры опций) */
	if (fnamekey != NULL) {
//		keyfile = fopen ("/home/sasha/development/essno/Debug/ekey", "rt");
		keyfile = fopen (fnamekey, "rt");
		if (keyfile == NULL) {
			fprintf (stderr, "Не могу открыть файл (%s)\n", fnamekey);
			return 1;
		};
	};

	if (fnamein != NULL) {
//		infile = fopen ("/home/sasha/development/essno/Debug/cf", "rt");
		infile = fopen (fnamein, "rb");
		if (infile == NULL) {
			fprintf (stderr, "Не могу открыть файл (%s)\n", fnamein);
			return 1;
		};
	};
	
	if (fnameout != NULL) {
//		outfile = fopen ("/home/sasha/development/essno/Debug/output", "rt");
		outfile = fopen (fnameout, "wt");
		if (outfile == NULL) {
			fprintf (stderr, "Не могу открыть файл (%s) на запись. \n", fnameout);
			return 1;
		};
	};

	/*Подготавливаем принимающие буфера*/
	char sbuf [MAX_BUF_IN];  memset( sbuf, 0x00, MAX_BUF_IN); 
	// Модуль эллиптической кривой: p
	char p_in_dec [MAX_BUF_IN];  memset( p_in_dec, 0x00, MAX_BUF_IN);  
	// Коэффициенты эллиптической кривой: a, b
	char a_in_dec [MAX_BUF_IN];  memset( a_in_dec, 0x00, MAX_BUF_IN);
	char b_in_dec [MAX_BUF_IN];  memset( b_in_dec, 0x00, MAX_BUF_IN);
	// Порядок группы точек эллиптической кривой
	char m_in_dec [MAX_BUF_IN];  memset( m_in_dec, 0x00, MAX_BUF_IN);
	// Порядок циклической подгруппы группы точек эллиптической кривой
	char q_in_dec [MAX_BUF_IN];  memset( q_in_dec, 0x00, MAX_BUF_IN);
	// Коэффициенты точки эллиптической кривой P
	char xP_in_dec [MAX_BUF_IN];  memset( xP_in_dec, 0x00, MAX_BUF_IN);
	char yP_in_dec [MAX_BUF_IN];  memset( yP_in_dec, 0x00, MAX_BUF_IN);
	// Ключ подписи
	char d_in_dec [MAX_BUF_IN];  memset( d_in_dec, 0x00, MAX_BUF_IN);
	// Ключ проверки
	char xQ_in_dec [MAX_BUF_IN];  memset( xQ_in_dec, 0x00, MAX_BUF_IN);
	char yQ_in_dec [MAX_BUF_IN];  memset( yQ_in_dec, 0x00, MAX_BUF_IN);
	// Подпись
	char ksi_in_dec [MAX_BUF_IN];  memset( ksi_in_dec, 0x00, MAX_BUF_IN);
	
	/*Считываем параметры эллиптической кривой*/
	void *rch=NULL;
	do{
		rch = fgets( sbuf, MAX_BUF_IN+1, keyfile); 
		printf( "sbuf=%s", sbuf);		
		
		switch ( sbuf[0] ) {
			case 'p':
				memcpy( p_in_dec, sbuf+2, strlen(sbuf)-3 );
				printf ("p_in_dec=%s, strlen=%d \n", p_in_dec, strlen(p_in_dec));
				break;
			case 'a':
				memcpy( a_in_dec, sbuf+2, strlen(sbuf)-3 );
				printf ("a_in_dec=%s, strlen=%d \n", a_in_dec, strlen(a_in_dec) );
				break;
			case 'b':
				memcpy( b_in_dec, sbuf+2, strlen(sbuf)-3 );
				printf ("b_in_dec=%s, strlen=%d \n", b_in_dec, strlen(b_in_dec) );
				break;
			case 'm':
				memcpy( m_in_dec, sbuf+2, strlen(sbuf)-3 );
				break;
			case 'q':
				memcpy( q_in_dec, sbuf+2, strlen(sbuf)-3 );
				break;
			case 'd':
				memcpy( d_in_dec, sbuf+2, strlen(sbuf)-3 );
				break;

			case 'x':
				if( sbuf[1]=='P' )
					memcpy( xP_in_dec, sbuf+3, strlen(sbuf)-4 );
				if( sbuf[1]=='Q' )
					memcpy( xQ_in_dec, sbuf+3, strlen(sbuf)-4 );			
				break;
			case 'y':
				if( sbuf[1]=='P' )
					memcpy( yP_in_dec, sbuf+3, strlen(sbuf)-4 );
				if( sbuf[1]=='Q' )
					memcpy( yQ_in_dec, sbuf+3, strlen(sbuf)-4 );			
				break;
			
			case 'k':
				if( sbuf[1]=='s' && sbuf[2]=='i' )
					memcpy( ksi_in_dec, sbuf+4, strlen(sbuf)-5 );
			default:
				break;
		}		
		
		memset( sbuf, 0x00, MAX_BUF_IN); 
	}while( rch != NULL);
	
//-----

//-----
	/*Инициализация глобальных переменных*/
	initGlobal();
	
	/*Инициализация переменных кривой*/
	NEW_BN( p_, p, 0, strlen(p_in_dec) );
	loadBN_decimal( p, p_in_dec, strlen(p_in_dec) );
	
	NEW_BN( a_, a, 0, strlen(a_in_dec) );
	loadBN_decimal( a, a_in_dec, strlen(a_in_dec) );
	
	NEW_BN( b_, b, 0, strlen(b_in_dec) );
	loadBN_decimal( b, b_in_dec, strlen(b_in_dec) );

	NEW_BN( m_, m, 0, strlen(m_in_dec) );
	loadBN_decimal( m, m_in_dec, strlen(m_in_dec) );
		
	NEW_BN( q_, q, 0, strlen(q_in_dec) );
	loadBN_decimal( q, q_in_dec, strlen(q_in_dec)  );

	NEW_BN( xP_, xP, 0, strlen(xP_in_dec) );
	loadBN_decimal( xP, xP_in_dec, strlen(xP_in_dec)  );
	
	NEW_BN( yP_, yP, 0, strlen(yP_in_dec) );
	loadBN_decimal( yP, yP_in_dec, strlen(yP_in_dec)  );

	Dot P_;
	Dot *P=&P_;
	P->x=xP;
	P->y=yP;

	NEW_BN( d_, d, 0, strlen(d_in_dec));
	loadBN_decimal( d, d_in_dec, strlen(d_in_dec) );

	NEW_BN( xQ_, xQ, 0, strlen(xQ_in_dec));
	loadBN_decimal( xQ, xQ_in_dec, strlen(xQ_in_dec) );	
	
	NEW_BN( yQ_, yQ, 0, strlen(yQ_in_dec));
	loadBN_decimal( yQ, yQ_in_dec, strlen(yQ_in_dec) );
	
	Dot Q_;
	Dot *Q=&Q_;
	Q->x=xP;
	Q->y=yP;

	NEW_BN( ksi_, ksi, 512, 0);		// ЭЦП (512 бит)
	NEW_BN( a_H_, a_H, 256, 0);		// хэш сообщения (256 бит)
//============================================================================================//
	
test:
	if( testt==1 )
		initGlobal();
	/*Переменные тестирования*/
	int max_leng_BN = MAX_BUF_IN;
	//int max_leng_BN = BN_MAX_DEC;
	
	NEW_BN( BN_1_, BN_1, 0, max_leng_BN);	
	NEW_BN( BN_2_, BN_2, 0, max_leng_BN);
	NEW_BN( BN_3_, BN_3, 0, max_leng_BN);
	NEW_BN( BN_4_, BN_4, 0, max_leng_BN);
	NEW_BN( BN_5_, BN_5, 0, max_leng_BN);

	Dot DBN_;
	Dot *DBN=&DBN_;
	DBN->x=BN_1;
	DBN->y=BN_2;

	Dot DBN_2_;
	Dot *DBN_2=&DBN_2_;
	DBN_2->x=BN_3;
	DBN_2->y=BN_4;

//614891501192740863 = "368047291105198416" =	888888F FFFFFFFF = 1000 1000 1000 1000 1000 1000   1111 1111 1111 1111 1111 1111 1111 1111 1111
//68719476735 = "53767491786" = F FFFFFFFF = 1111 1111 1111 1111 1111 1111 1111 1111 1111
//=8947848
// (803794811^-1) ( mod 5789604461) = 3109191382
//=614891501192740863*16780801 + 68719476735*-150152073449234=273
//-150152073449234 + 614891501192740863 = 614741349119291629
//2401919926534143 =8888 88FF FFFF F
//268435455		=          FF FFFF F

//4294967295 = "5927694924" = FFFFFFFF = 1111 1111 1111 1111 1111 1111 1111 1111
//2290649224 = "4229460922" = 88888888 = 1000 1000 1000 1000 1000 1000 1000 1000
//(1344674664085480935)9658268985295259228   -  686405678790221707
	char input_d[]="0"; // В прямом порядке
	char input_d_2[]="0"; // В прямом порядке
	char input_d_3[]="0";


//	printf("Hello! \n");

//	BN_1->binary[0]=0x88888889;
	PRINT_BN(BN_1);	

//	loadBN_binary( BN_1, input_d, sizeof(input_d)-1 );
	loadBN_decimal( BN_1, input_d, sizeof(input_d)-1 );
	loadBN_decimal( BN_2, input_d_2, sizeof(input_d_2)-1 );
	loadBN_decimal( BN_3, input_d_3, sizeof(input_d_3)-1 );

	//PRINT_BN(BN_1);



//sumDot_Dot( DBN, P, P, p, a);
//sumDot_Dot( DBN_2, DBN, DBN, p, a);
//mulBN_Dot_dec( DBN_2, BN_1, P, p, a);
//MUL_BN_DOT_DEC( DBN, BN_3, P, p, a);
//encrypt_elliptic( 	p, a, b, m, q, xP, yP,  d,	a_H, ksi );

//	PRINT_BN_DEC(BN_1);

//addBN_BN_dec( BN_1, BN_2, 2);
//PRINT_BN_DEC(BN_1);
//	PRINT_BN_DEC(BN_2);
//	printf("\n\nmaxBN_BN_dec( BN_1, BN_2)=%d",maxBN_BN_dec( BN_1, BN_2));

//euclidBN_BN_dec( BN_1, BN_2, BN_3, BN_4, BN_5);
//divBN_BN_dec( BN_1, BN_2, BN_3, BN_4);
//subBN_BN_dec( BN_1, BN_2, 0);

//muladdBN_dec( BN_1, 3, 0);
mulBN_BN_dec( BN_3, BN_1, BN_2);
//mulBN_BN_dec( BN_4, BN_1, BN_2);
//modBN_BN_dec( BN_1, BN_1, BN_2);
//divBN_BN_dec( BN_4, BN_1, BN_2, BN_3);

/*	int l=0;
	for(l=0; l<10; l++)
		addBN_BN_dec( BN_1, BN_2, 0);*/
/*	do{
	
	}while( subBN_BN_dec( BN_1, BN_2, 1) !=0);*/
/*	int i=0;
	printf("\n\n subBN_BN_dec( BN_1, BN_2, 1): ");
	int t=1;
	for(i=0; t!=0; i++){
		t = subBN_BN_dec( BN_1, BN_2, 1);
		printf("\ni=%d, subBN_BN_dec( BN_1, BN_2, 1)=%d", i,t );
	};*/

	synchBN( BN_1, 10);
//   		 printf("cgDec=%d, cgBin=%d \n", cgDec, cgBin);
	
	printf("\nBN_1_BIN: ");		PRINT_BN_BIN(BN_1);
	printf("\n BN_1_DEC: ");	PRINT_BN_DEC(BN_1);
	PRINT_BN( BN_1);
	
	printf("\n BN_2_DEC: ");	PRINT_BN_DEC(BN_2);
	PRINT_BN(BN_2);	
	
	printf("\n BN_3_DEC: ");	PRINT_BN_DEC(BN_3);
	PRINT_BN(BN_3);	

/*	printf("\n BN_4_DEC: ");	PRINT_BN_DEC(BN_4);
	PRINT_BN(BN_4);

	printf("\n BN_5_DEC: ");	PRINT_BN_DEC(BN_5);
	PRINT_BN(BN_5);	*/

	if( testt==0){	
		clearBN( p);
		clearBN( a);
		clearBN( b);
		clearBN( m);
		clearBN( q);
		clearBN( xP);
		clearBN( yP);
		clearBN( d);
		clearBN( xQ);
		clearBN( yQ);
		clearBN( ksi);
		clearBN( a_H);
	};
	
	clearBN( BN_1);
	clearBN( BN_2);
	clearBN( BN_3);
	clearBN( BN_4);
	clearBN( BN_5);
	
	clearGlobal();
	
	if( testt==0){
		fclose(keyfile);
		fclose(infile);
		fclose(outfile);
	};
	
	return 0;
}


int encrypt_elliptic( 	BigNumber *p, BigNumber *a, BigNumber *b, BigNumber *m, BigNumber *q,
						BigNumber *xP, BigNumber *yP,  BigNumber *d,
						BigNumber *a_H, BigNumber *ksi ){
	/* Вход: d - ключ подписи
	 * 		a_H - бинарный хэш сообщения M
	 * 		параметры эллиптической кривой
	 * Выход: ksi - цифровая подпись 
	 * 											*/

	/*Параметры сообщения (шаги 1 – 3  по Алгоритму I (6.1) - ГОСТ 34.10-01 )*/ 
	// e = a (mod q) , где a - двоичное представление h
	char e_in_dec[]="20798893674476452017134061561508270130637142515379653289952617252661468872421";
	// 0 < k< q, k-псевдослучайное целое число
	char k_in_dec[]="53854137677348463731403841147996619241504003434302020712960838528893196233395"; 
	
	Dot P_;
	Dot *P=&P_;
	P->x=xP;
	P->y=yP;
	
	int max_leng = p->leng_dec*4;
	/*Внутренние переменные*/
	NEW_BN( e_, e, 0, max_leng);
	NEW_BN( r_, r, 0, max_leng);
	NEW_BN( s_, s, 0, max_leng);

	/*Точка C*/
	NEW_BN( xC_, xC, 0, max_leng);
	NEW_BN( yC_, yC, 0, max_leng);

	Dot C_;
	Dot *C=&C_;
	C->x=xC;
	C->y=yC;
	
	/*Случайное число k*/
	NEW_BN( k_, k, 0,  q->leng_dec);		// |k|=|q|  (k<0<q)

	
	/*Шаг 1 - вычислить хэш код сообщения*/
	// a_H - входное значение хэша
	
	/*Шаг 2 - вычислить целое число a_H-десятичное представление хэша */
	synchBN( a_H, 2);

	/*Шаг 2 – : определить e=a_H (mod q) */ 
/*	modBN_BN_dec( e, a_H, q);
	if( maxBN_BN_dec( e, NULL_BN)==0)
		EQ_BN_BN_DEC( e, ONE_BN);*/
loadBN_decimal( e, e_in_dec, sizeof(e_in_dec)-1 );
synchBN( e, 10);
printf("\n e_BIN: ");	PRINT_BN_BIN(e);
printf("\n e_DEC: ");	PRINT_BN_DEC(e);
PRINT_BN(e);

step3:	
	/*Шаг 3 - генерация псевдослучайного целого числа k: 0 < k< q*/
/*	do{
		ess_random( k->binary, k->leng_dec );
		synchBN( k, 2);
	}while( !(maxBN_BN_dec( k, NULL_BN)==1 
			  && maxBN_BN_dec( k, q)==2   )  );*/
loadBN_decimal( k, k_in_dec, sizeof(k_in_dec)-1 );
synchBN( k, 10);
printf("\n k_BIN: ");	PRINT_BN_BIN(k);
printf("\n k_DEC: ");	PRINT_BN_DEC(k);
PRINT_BN(k);	
	/*Шаг 4 – вычислить точку эллиптической кривой C=kP=P+P+P+...+P (k раз)*/
//	MUL_BN_DOT_DEC( C, k, P, p, a);
	mulBN_Dot_dec( C, k, P, p, a);

printf("\n== Cx_DEC= "); PRINT_BN_DEC( C->x); PRINT_BN( C->x);
printf("\n== Cy_DEC= "); PRINT_BN_DEC( C->y); PRINT_BN( C->y);
	
	/*Шаг 4 - определяем  r = xC (mod q);*/
	modBN_BN_dec( r, C->x, q);
	/*Если r=0, то вернуться к шагу 3*/
	if( maxBN_BN_dec( r, NULL_BN)==0)
		goto step3;
	
	/*Шаг 5 - Вычислить  s = (rd + ke) (mod q)*/
	mulBN_BN_dec( xC, r, d);		// xC, yC - как временные
	 modBN_BN_dec( xC, xC, q);
	mulBN_BN_dec( yC, k, e);
	 modBN_BN_dec( yC, yC, q);		
	addBN_BN_dec( xC, yC, 0);
	 modBN_BN_dec( xC, xC, q);
	EQ_BN_BN_DEC( s, xC);
	/*Если s=0, то вернуться к шагу 3*/
	if( maxBN_BN_dec( s, NULL_BN)==0)
		goto step3;

	/*Шаг 6 - вычислить двоичные представления r и s*/
	synchBN( r, 10);
	synchBN( s, 10);
	
	/*Шаг 6 - определить  ksi = (r||s)   как конкатенацию двух двоичных векторов*/
	/* (Внутреннее представление - по группам из 32 бит) */
	memset(ksi->binary, 0x00, (int) (gMEM_FOR_BIN(ksi,2)/4) );
	
	memcpy( ksi->binary, s->binary, 256/32 );
	memcpy( ksi->binary + (256/32), r->binary, 256/32 );
	ksi->leng_bin = 512;
	ksi->grp_bin_max = 512/32;
					
	/*Выход*/
	clearBN( e);
	clearBN( r);
	clearBN( s);
	clearBN( xC);
	clearBN( yC);
	clearBN( k);

	return 0;
}  

int decrypt_elliptic( 	BigNumber *p, BigNumber *a, BigNumber *b, BigNumber *m, BigNumber *q, 		\
						BigNumber *xP, BigNumber *yP, BigNumber *xQ, BigNumber *yQ,\
						BigNumber *a_H, BigNumber *ksi  ){
	/*Вход: ksi - ЭЦП
	 * 		a_H - хэш сообщения
	 * 		параметры кривой
	 *Выход:	"111" -	ЭЦП верна	(соответствие подписи сообщению)
	 * 			"0"	  - ЭЦП ошибочна (подпись не соответствует сообщению)  */
	
	
	Dot P_;
	Dot *P=&P_;
	P->x=xP;
	P->y=yP;

	Dot Q_;
	Dot *Q=&Q_;
	Q->x=xQ;
	Q->y=yQ;
	
	int max_leng = p->leng_dec*4;
	/*Внутренние переменные*/
	NEW_BN( e_, e, 0, max_leng);
	NEW_BN( r_, r, 0, max_leng);
	NEW_BN( s_, s, 0, max_leng);

	/*Точка C*/
	NEW_BN( xC_, xC, 0, max_leng);
	NEW_BN( yC_, yC, 0, max_leng);

	Dot C_;
	Dot *C=&C_;
	C->x=xC;
	C->y=yC;
	
	/*Точка C1*/
	NEW_BN( xC1_, xC1, 0, max_leng);
	NEW_BN( yC1_, yC1, 0, max_leng);

	Dot C1_;
	Dot *C1=&C1_;
	C1->x=xC1;
	C1->y=yC1;
		
	/*Точка C2*/
	NEW_BN( xC2_, xC2, 0, max_leng);
	NEW_BN( yC2_, yC2, 0, max_leng);

	Dot C2_;
	Dot *C2=&C2_;
	C2->x=xC2;
	C2->y=yC2;

	/*Числа z1, z2, v */
	NEW_BN( z1_, z1, 0, BN_MAX_DEC);
	NEW_BN( z2_, z2, 0, BN_MAX_DEC);
	NEW_BN( v_,   v, 0, BN_MAX_DEC);	


	/*Загрузка s и r из ЦП*/
	memcpy( s->binary, ksi->binary,  256/32);
	s->leng_bin = 256;
	s->grp_bin_max = 256/32;

	memcpy( r->binary, ksi->binary + (256/32), 256/32 );
	r->leng_bin = 256;
	r->grp_bin_max = 256/32;

	/*Шаг 1 - вычисление целых чисел s и r*/
	synchBN( s, 2);
	synchBN( r, 2);
	
	/*Шаг 1 - проверка неравенств: 0<r<q; 0<s<q*/
	if( !(maxBN_BN_dec( r, NULL_BN)==1 
			  && maxBN_BN_dec( r, q)==2   ) )
		return 0;
	if( !(maxBN_BN_dec( s, NULL_BN)==1 
			  && maxBN_BN_dec( s, q)==2   ) )
		return 0;

	/*Шаг 2 - вычислить хэш код сообщения*/
	// a_H - входное значение хэша
	
	/*Шаг 3 - вычислить целое число a_H-десятичное представление хэша */
	synchBN( a_H, 2);

	/*Шаг 3 – определить: e=a (mod q) */ 
	modBN_BN_dec( e, a_H, q);
	if( maxBN_BN_dec( e, NULL_BN)==0)
		EQ_BN_BN_DEC( e, ONE_BN);	
	
	/*Шаг 4 - вычислить v=e^-1 (mod q) */
	euclidBN_BN_dec( e, q, v, z1, z2);		//z1, z2 - как временные
	
	/*Шаг 5 - вычислить z1=sv (mod q)*/
	mulBN_BN_dec( z1, s, v);
	 modBN_BN_dec( z1, z1, q);
	
	/*Шаг 5 - вычислить z2=-rv (mod q)*/
	modBN_BN_dec( xC, r, q);		//Остаток -(r mod q)
	EQ_BN_BN_DEC( yC, q);
	subBN_BN_dec( yC, xC, 0);		// yC=( -r mod q)
	
	mulBN_BN_dec( z2, yC, v);		// z2=-r*v (mod q)
	  modBN_BN_dec( z2, z2, q);

	/*Шаг 6 - вычислить точку   C = C1 + C2 = z1*P + z2*Q  */
	MUL_BN_DOT_DEC( C1, z1, P, p, a);
	MUL_BN_DOT_DEC( C2, z2, Q, p, a);

	sumDot_Dot( C, C1, C2, p, a);

	/*Шаг 6 - определить  R=xC (mod q) */
	modBN_BN_dec( xC, xC, q);	// xC=R
	
	/*Шаг 7 - проверить равенство:  R=r  */
	if( maxBN_BN_dec( xC, r)==0 )
		return 111;


	clearBN( e);
	clearBN( r);
	clearBN( s);	

	clearBN( xC);
	clearBN( yC);
	clearBN( xC1);
	clearBN( yC1);
	clearBN( xC2);
	clearBN( yC2);

	clearBN( z1);
	clearBN( z2);
	clearBN( v);

	return 0;
}



/*
*  Брюс Шнайер - Прикладная криптография, гл. 16.2
*/
int LFSR ( ) {
	// Вход: -
	// Выход: поток случайных бит
     static unsigned long long ShiftRegister = 1;
     
     /* Примитивный многочлен по модулю 2: (64,4,3,1,0):
      * Сдвигая регистр, приводим нужные биты 
      * на первую позицию; XOR; выделяем первый бит;
      * ставим его на 64 позицию;
      * накладываем операц. ИЛИ на сдвинутый вправо на 1 бит весь Регистр */
     ShiftRegister = (	(((ShiftRegister >> 63)
			            ^(ShiftRegister >> 3)
			            ^(ShiftRegister >> 2)
			            ^ShiftRegister)
            & 0x0000000000000001)  
            <<63) 
            | (ShiftRegister >> 1) ;
	//Поток начинается со второго бита
     return ShiftRegister & 0x0000000000000001;
}


void ess_random(u_int * pRand, u_int length_b) {
	// Вход:- указатель на участок памяти для передачи бит
	//		- длина генерируемого случайного числа в битах
	// Выход: целое случайное число	

	// Случайная точка подключения к потоку LFSR	
	// Пропускаем "ненужный" поток
	srand((unsigned)time(NULL));	// Инициализация rand
	int i=0;

	for(i=0; i<rand(); i++)
		LFSR();
	
	// Буфер, накапливающий биты по 32
	// (Он один, поскольку рассчитан на произвольную длину сл.числа)
	u_int BufferBits=0;
	
	// Обрабатываем каждый поступивший LFSR бит, записывая в буфер
	for(i=0; i<length_b; i++){
		if( LFSR()==1 ){
			BufferBits<<=1;
			BufferBits|=0x00000001;	// 1
		}
		else
			BufferBits<<=1;			// 0
		
		// Каждые 32 бита сбрасываем буфер в память
		if( (i%32==0) && (i!=0) ){
			memset(pRand + ((int)i/32), BufferBits, 1);
			BufferBits = 0;
		};
	};
	
}

/*Инициализация глобальных переменных*/
void initGlobal( void ){
	
	/*Нулевая и единичная переменные*/
	NULL_BN=&NULL_BN_;
	NULL_BN->leng_bin =0;
	NULL_BN->leng_dec =1;
	initBN( NULL_BN);
	NULL_BN->decimal [0]=0;

	ONE_BN=&ONE_BN_;
	ONE_BN->leng_bin =0;
	ONE_BN->leng_dec =1;
	initBN( ONE_BN);
	ONE_BN->decimal [0]=1;


	/*Переменные ф-ции умножения БЧ: mulBN_BN_dec*/
	B_2=&B_2_;
	B_2->leng_dec=BN_MAX_DEC;
	B_2->leng_bin=0;
	initBN( B_2);
	
	B_3=&B_3_;
	B_3->leng_dec = BN_MAX_DEC;
	B_3->leng_bin = 0;
	initBN( B_3);
	
	B_4=&B_4_;
	B_4->leng_dec = BN_MAX_DEC;
	B_4->leng_bin = 0;
	initBN( B_4);
	
	B_5=&B_5_;
	B_5->leng_dec = BN_MAX_DEC;
	B_5->leng_bin = 0;
	initBN( B_5);
	
	B_6=&B_6_;
	B_6->leng_dec = BN_MAX_DEC;
	B_6->leng_bin = 0;
	initBN( B_6);
	
	B_7=&B_7_;
	B_7->leng_dec = BN_MAX_DEC;
	B_7->leng_bin = 0;
	initBN( B_7);

	B_8=&B_8_;
	B_8->leng_dec = BN_MAX_DEC;
	B_8->leng_bin = 0;
	initBN( B_8);
	
	B_9=&B_9_;
	B_9->leng_dec = BN_MAX_DEC;
	B_9->leng_bin = 0;
	initBN( B_9);
	
	/*Переменные ф-ции сложения точек: sumDot_Dot*/
	LL=&LL_;
	LL->leng_bin =0;
	LL->leng_dec =BN_MAX_DEC;
	initBN( LL);
	
	Ab=&Ab_;
	Ab->leng_bin=0;
	Ab->leng_dec=BN_MAX_DEC;
	initBN( Ab);
	
	Bl=&Bl_;
	Bl->leng_bin=0;
	Bl->leng_dec=BN_MAX_DEC;
	initBN( Bl);	
	
	
	XX=&XX_;
	XX->leng_bin =0;
	XX->leng_dec =BN_MAX_DEC;
	initBN( XX);
	
	YY=&YY_;
	YY->leng_bin =0;
	YY->leng_dec =BN_MAX_DEC;
	initBN( YY);
	
	DD=&DD_;
	DD->leng_bin =0;
	DD->leng_dec =BN_MAX_DEC;
	initBN( DD);
	
	/*Переменные ф-ции Расширенного алгоритма Евклида: euclidBN_BN_dec*/
	ecA=&ecA_;					//Копии входящих переменных
	ecA->leng_bin =0;			
	ecA->leng_dec = BN_MAX_DEC;
	initBN( ecA);
		
	ecB=&ecB_;
	ecB->leng_bin =0;
	ecB->leng_dec = BN_MAX_DEC;	
	initBN( ecB);
	
	eT1=&eT1_;					//Временные
	eT1->leng_bin =0;
	eT1->leng_dec = BN_MAX_DEC;
	initBN( eT1);
	
	eT2=&eT2_;
	eT2->leng_bin =0;
	eT2->leng_dec = BN_MAX_DEC;
	initBN( eT2);	
	
	eQ=&eQ_;					//число вхождений B в A
	eQ->leng_bin =0;
	eQ->leng_dec = BN_MAX_DEC;
	initBN( eQ);
	
	eR=&eR_;					//Остаток от вхождений
	eR->leng_bin =0;
	eR->leng_dec = BN_MAX_DEC;
	initBN( eR);
	
	eX1=&eX1_;					//Матрица вида:  	( X2  X1 )
	eX1->leng_bin =0;			//					( Y2  Y1 )
	eX1->leng_dec = BN_MAX_DEC;
	initBN( eX1);
	
	eX2=&eX2_;
	eX2->leng_bin =0;
	eX2->leng_dec = BN_MAX_DEC;
	initBN( eX2);

	eY1=&eY1_;
	eY1->leng_bin =0;
	eY1->leng_dec = BN_MAX_DEC;
	initBN( eY1);

	eY2=&eY2_;
	eY2->leng_bin =0;
	eY2->leng_dec = BN_MAX_DEC;
	initBN( eY2);

	/*Переменные ф-ции числа вхождений B в A: divBN_BN_dec*/
	enTT=&enTT_;
	enTT->leng_dec =0;
	enTT->leng_bin =32;
	initBN( enTT);
	
	/*Переменная ф-ции вычитания ускоренного (копия делителя*10^x)*/
	tmas_d = NULL;
	tmas_d = ess_malloc( BN_MAX_DEC );
	

	return;	
}


void clearGlobal( void ){

	clearBN( ONE_BN);
	clearBN( NULL_BN);

	clearBN( B_2);
	clearBN( B_3);
	clearBN( B_4);
	clearBN( B_5);
	clearBN( B_6);
	clearBN( B_7);
	clearBN( B_8);
	clearBN( B_9);

	clearBN( LL);
	clearBN( Ab);
	clearBN( Bl);
	clearBN( XX);
	clearBN( YY);
	clearBN( DD);
	
	clearBN( ecA);
	clearBN( ecB);
	clearBN( eT1);
	clearBN( eT2);
	clearBN( eQ);
	clearBN( eR);
	clearBN( eX1);
	clearBN( eX2);
	clearBN( eY1);
	clearBN( eY2);
//printf("Hello! \n");

	clearBN( enTT);
	
	free( tmas_d);
	
	return;
}

